package snake3d.main;
import java.util.ArrayList;
import processing.opengl.*;
import processing.core.*;
import peasy.*;

public class Cenario extends PApplet {	
	
	private PeasyCam cam; //PeasyCam permite controle da camara pelo mouse
	int i, j, k; //variaveis utilizadas para criar o grid
    int tamanhoSnake; //tamanho atual da snake
    ArrayList snakeX = new ArrayList(); //vetor das posicoes em X de cada parte do corpo da snake
    ArrayList snakeY = new ArrayList(); //idem para posicoes em Y
    ArrayList snakeZ = new ArrayList(); //idem para posicoes em Z
    int[] direcao = new int[3]; //vetor direcao do movimento da snake
    int tamanhoGrid; //quantas boxes o grid tera de largura, comprimento e altura
    int alimentoX, alimentoY, alimentoZ; //posicao do alimento
    boolean alimentoAtivo; //alimento esta na tela ou foi comido pela snake?
    boolean gameOver; //usuario perdeu o jogo?
    boolean controleUsuario; //usuario pode alterar a direcao do movimento?
    int contador; //contador para reduzir velocidade do loop do draw e controlar movimento automatico da snake
	
	public float degToRad(float deg) {
		return (float) (deg*3.14159265/180.0);
	}
	
	public void setup(){
		size(640, 640, P3D);
		
        cam = new PeasyCam(this,300); 
        cam.setMinimumDistance(50);
        cam.setMaximumDistance(1000);
        
        tamanhoGrid = 7;
        tamanhoSnake = 1;
        contador = 0;
        alimentoAtivo = false;
        gameOver = false;
        controleUsuario = true;
        
        //definindo posicao e direcao iniciais da snake
        for (i=0; i<tamanhoSnake; i++)
        {
        snakeX.add(0,0);
        snakeY.add(0,0);
        snakeZ.add(0,0);
        }
        direcao[0] = 1;
        direcao[1] = 0;
        direcao[2] = 0;
        
	}

	public void draw() {
	
		//soh movimentar o snake a cada N loops do draw
		if (contador++%30 == 0) {
			
			//apos certo limite, precisamos zerar o contador porque int tem um limite maximo
			if (contador>=40000) contador = 0;
		  
			//a posicao de cada parte do corpo da snake vira a posicao da parte anterior
			for(i = tamanhoSnake-2; i >= 0; i--) {
	            snakeX.add(i+1, (Integer)snakeX.get(i));
	            snakeY.add(i+1, (Integer)snakeY.get(i));
	            snakeZ.add(i+1, (Integer)snakeZ.get(i));
	        }
			//a cabeca da snake sera a posicao anterior mais o vetor direcao
			snakeX.add(0,(Integer)snakeX.get(0) + direcao[0]);
			snakeY.add(0,(Integer)snakeY.get(0) + direcao[1]);
			snakeZ.add(0,(Integer)snakeZ.get(0) + direcao[2]);
			//se a snake ultrapassa os limites do grid, aparece na parede oposta
	        if ((Integer)snakeX.get(0) >= tamanhoGrid) snakeX.add(0,0);
	        if ((Integer)snakeY.get(0) >= tamanhoGrid) snakeY.add(0,0);
	        if ((Integer)snakeZ.get(0) >= tamanhoGrid) snakeZ.add(0,0);
	        if ((Integer)snakeX.get(0) < 0) snakeX.add(0,tamanhoGrid-1);
	        if ((Integer)snakeY.get(0) < 0) snakeY.add(0,tamanhoGrid-1);
	        if ((Integer)snakeZ.get(0) < 0) snakeZ.add(0,tamanhoGrid-1);
	        controleUsuario = true; //movimento da snake realizado, portanto usuario ja pode alterar novamente a direcao
        }
        
		//salvando informacoes da proxima posicao da cabeca da snake
		int proximoX = (Integer)snakeX.get(0)+direcao[0];
		int proximoY = (Integer)snakeY.get(0)+direcao[1];
		int proximoZ = (Integer)snakeZ.get(0)+direcao[2];
		if (proximoX >= tamanhoGrid) proximoX = 0;
        if (proximoY >= tamanhoGrid) proximoY = 0;
        if (proximoZ >= tamanhoGrid) proximoZ = 0;
        if (proximoX < 0) proximoX = tamanhoGrid-1;
        if (proximoY < 0) proximoY = tamanhoGrid-1;
        if (proximoZ < 0) proximoZ = tamanhoGrid-1;
        
        //se a snake vai colidir com seu proprio corpo, game over
        for(i = 0; i < (tamanhoSnake-1); i++) { //usamos (tamanhoSnake-1) pois essa verificao nao deve ser feita para a ultima parte do corpo, que deixara um espaco vazio apos seu proximo movimento
	        if ((Integer)snakeX.get(i) == proximoX && (Integer)snakeY.get(i) == proximoY && (Integer)snakeZ.get(i) == proximoZ) {
	        	gameOver = true;
	        }
        }
        
        //se a snake vai comer o alimento, snake cresce englobando o alimento
        if (alimentoX == proximoX && alimentoY == proximoY && alimentoZ == proximoZ) {
        	alimentoAtivo = false;
            tamanhoSnake = tamanhoSnake + 1;
            for(i = tamanhoSnake-2; i >= 0; i--) {
	            snakeX.add(i+1, (Integer)snakeX.get(i));
	            snakeY.add(i+1, (Integer)snakeY.get(i));
	            snakeZ.add(i+1, (Integer)snakeZ.get(i));
	 	    }
	 		//a cabeca da snake sera a posicao do alimento
	 		snakeX.add(0, alimentoX);
	 		snakeY.add(0, alimentoY);
	 		snakeZ.add(0, alimentoZ);
        }
        
        //se nao ha alimento no grid, geramos alimento com posicao aleatoria
        if (alimentoAtivo == false){
        	alimentoX = (int) random(tamanhoGrid-1);
            alimentoY = (int) random(tamanhoGrid-1);
            alimentoZ = (int) random(tamanhoGrid-1);
            //se o alimento se sobrepor a qualquer parte do corpo da snake, redefinimos a posicao do alimento
            for(i = 0; i < tamanhoSnake; i++)
            {
		        while (alimentoX == (Integer)snakeX.get(i) && alimentoY == (Integer)snakeY.get(i) && alimentoZ == (Integer)snakeZ.get(i)) {
		            alimentoX = (int) random(tamanhoGrid-1);
		            alimentoY = (int) random(tamanhoGrid-1);
		            alimentoZ = (int) random(tamanhoGrid-1);
		        }
            }
            alimentoAtivo = true;
        }
		
        //definindo caracteristicas do grid
        background(0);
        lights();
        translate(58, 48, 0);
        stroke(255);
        noFill();
        
        //criacao do grid
        for(k = 0; k < tamanhoGrid; k++)
        {
        	for(j = 0; j < tamanhoGrid; j++)
        	{
        		for(i = 0; i < tamanhoGrid; i++)
        		{
        			if (!gameOver) { //verifica se ainda nao foi game over
	        			//destacando no eixo X a cabeca da snake
	        			if (j==(Integer)snakeY.get(0) && k==(Integer)snakeZ.get(0)) {
	        				stroke(0,255,0,80);                             
	        			}
	        			//destacando no eixo Y a cabeca da snake
	        			if (i==(Integer)snakeX.get(0) && k==(Integer)snakeZ.get(0)) {
	        				stroke(0,255,0,80);                             
	        			}
	                    //destacando no eixo Z a cabeca da snake
	        			if (i==(Integer)snakeX.get(0) && j==(Integer)snakeY.get(0)) {
	        				stroke(0,255,0,80);                             
	        			}
	        			//destacando no eixo X o alimento
	        			if (j==alimentoY && k==alimentoZ) {
	        				stroke(255,0,0,80);                             
	        			}
	        			//destacando no eixo Y o alimento
	        			if (i==alimentoX && k==alimentoZ) {
	        				stroke(255,0,0,80);                             
	        			}
	                    //destacando no eixo Z o alimento
	        			if (i==alimentoX && j==alimentoY) {
	        				stroke(255,0,0,80);                             
	        			}
	        			//destacando eixo X
	        			if (j==0 && k==0) {
	        				stroke(255,0,0);                             
	        			}
	        			//destacando eixo Y
	        			if (i==0 && k==0) {
	        				stroke(0,255,0);                             
	        			}
	                    //destacando eixo Z
	        			if (i==0 && j==0) {
	        				stroke(0,0,255);                             
	        			}
	        			//se for a posicao do alimento, pintamos a box de vermelho
	        			if (i==alimentoX && j==alimentoY && k==alimentoZ) {
	        				fill(255,0,0);
	                    }
	        			//se for a posicao de alguma parte da snake, pintamos a box de verde
	                    for (int n = 0; n < tamanhoSnake; n++) {
	                    	if (i==(Integer)snakeX.get(n) && j==(Integer)snakeY.get(n) && k==(Integer)snakeZ.get(n)) {
	                    		fill(0,255,0);
	                    	}
	                    }
        			}
        			else fill(255,255,255);
		            box(50);
		            translate(50,0,0); //percorremos o eixo X criando boxes
		            noFill();
		            stroke(255,255,255,20); //o quarto parametro eh a transparencia
        		}
        		translate(-(50*tamanhoGrid),50,0); //voltamos ao inicio do eixo X e avancamos no eixo Y
        	}
            translate(0,-(50*tamanhoGrid),50); //voltamos ao inicio do eixo Y e avancamos no eixo Z
         }
	}

	//funcao que identifica comandos do usuario (w = cima; s = baixo; a = esqueda; d = direita)
	public void keyPressed() {
		if (controleUsuario == true) {
			//para cada diferente direcao, as teclas tem um impacto diferente
	        if (direcao[0]==1 && direcao[1]==0 && direcao[2]==0)
	        {
	        	//cada comando atualiza o vetor direcao
	        	if (key == 'a' || key == 'A') {
		            direcao[0] = 0;
		            direcao[1] = 1;
		            direcao[2] = 0;
	            }
	            if (key == 'd' || key == 'D') {
	                direcao[0] = 0;
	                direcao[1] = -1;
	                direcao[2] = 0;
	            }
	            if (key == 's' || key == 'S') {
	                direcao[0] = 0;
	                direcao[1] = 0;
	                direcao[2] = -1;
	            }
	            if (key == 'w' || key == 'W') {
	                direcao[0] = 0;
	                direcao[1] = 0;
	                direcao[2] = 1;
	            }
	        }
	        else if (direcao[0]==0 && direcao[1]==1 && direcao[2]==0) {
		        if (key == 'a' || key == 'A') {
		            direcao[0] = -1;
		            direcao[1] = 0;
		            direcao[2] = 0;
		        }
	            if (key == 'd' || key == 'D') {
	                direcao[0] = 1;
	                direcao[1] = 0;
	                direcao[2] = 0;
	            }
	            if (key == 's' || key == 'S') {
	                direcao[0] = 0;
	                direcao[1] = 0;
	                direcao[2] = -1;
	            }
	            if (key == 'w' || key == 'W') {
	                direcao[0] = 0;
	                direcao[1] = 0;
	                direcao[2] = 1;
	            }
	        }
	        else if (direcao[0]==0 && direcao[1]==-1 && direcao[2]==0)
	        {
	            if (key == 'a' || key == 'A') {
	                direcao[0] = 1;
	                direcao[1] = 0;
	                direcao[2] = 0;
	            }
	            if (key == 'd' || key == 'D') {
	                direcao[0] = -1;
	                direcao[1] = 0;
	                direcao[2] = 0;
	            }
	            if (key == 's' || key == 'S') {
	                direcao[0] = 0;
	                direcao[1] = 0;
	                direcao[2] = -1;
	            }
	            if (key == 'w' || key == 'W') {
	                direcao[0] = 0;
	                direcao[1] = 0;
	                direcao[2] = 1;
	            }
	        }
	        else if (direcao[0]==0 && direcao[1]==0 && direcao[2]==1)
	        {
	            if (key == 'a' || key == 'A') {
	                direcao[0] = 1;
	                direcao[1] = 0;
	                direcao[2] = 0;
	            }
	            if (key == 'd' || key == 'D') {
	                direcao[0] = -1;
	                direcao[1] = 0;
	                direcao[2] = 0;
	            }
	            if (key == 's' || key == 'S') {
	                direcao[0] = 0;
	                direcao[1] = -1;
	                direcao[2] = 0;
	            }
	            if (key == 'w' || key == 'W') {
	                direcao[0] = 0;
	                direcao[1] = 1;
	                direcao[2] = 0;
	            }
	        }
	        else if (direcao[0]==0 && direcao[1]==0 && direcao[2]==-1)
	        {
	            if (key == 'a' || key == 'A') {
	                direcao[0] = 1;
	                direcao[1] = 0;
	                direcao[2] = 0;
	            }
	            if (key == 'd' || key == 'D') {
	                direcao[0] = -1;
	                direcao[1] = 0;
	                direcao[2] = 0;
	            }
	            if (key == 's' || key == 'S') {
	                direcao[0] = 0;
	                direcao[1] = 1;
	                direcao[2] = 0;
	            }
	            if (key == 'w' || key == 'W') {
	                direcao[0] = 0;
	                direcao[1] = -1;
	                direcao[2] = 0;
	            }
	        }
	        else if (direcao[0]==-1 && direcao[1]==0 && direcao[2]==0)
	        {
	            if (key == 'a' || key == 'A') {
	                direcao[0] = 0;
	                direcao[1] = -1;
	                direcao[2] = 0;
	            }
	            if (key == 'd' || key == 'D') {
	                direcao[0] = 0;
	                direcao[1] = 1;
	                direcao[2] = 0;
	            }
	            if (key == 's' || key == 'S') {
	                direcao[0] = 0;
	                direcao[1] = 0;
	                direcao[2] = -1;
	            }
	            if (key == 'w' || key == 'W') {
	                direcao[0] = 0;
	                direcao[1] = 0;
	                direcao[2] = 1;
	            }
	        }
		}
        controleUsuario = false; //usuario soh podera alterar a direcao novamente apos o snake se mover
	}
}
